home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Frameworks / Grant's CGI Framework 1.0b14 / Util / LogUtil.c < prev    next >
Text File  |  1996-04-11  |  10KB  |  453 lines

  1. /*****
  2.  *
  3.  *    LogUtil.c
  4.  *
  5.  *    Logging functions
  6.  *
  7.  *    This is a support file for "Grant's CGI Framework".
  8.  *    Please see the license agreement that accompanies the distribution package
  9.  *    for licensing details.
  10.  *
  11.  *    Copyright ©1995,1996 by Grant Neufeld
  12.  *    grant@acm.com
  13.  *    http://arpp.carleton.ca/grant/mac/grantscgi/
  14.  *
  15.  *****/
  16.  
  17. #include "MyConfiguration.h"
  18. #if kCompileWithLogSupport
  19.  
  20. #if !kCompileWithProcessFileSpec
  21. #error "Logging requires the kCompileWithProcessFileSpec to be set on in MyConfiguration.h"
  22. #endif
  23.  
  24. #include <string.h>
  25.  
  26. #include "compiler_stuff.h"
  27.  
  28. #include "constants.h"
  29. #include "globals.h"
  30.  
  31. #include "DebugUtil.h"
  32. #include "FileUtil.h"
  33.  
  34. #include "LogUtil.h"
  35.  
  36.  
  37. /***  LOCAL VARIABLES  ***/
  38.  
  39. static OSErr    vLogInitialized = false;    /* logging has been initialized */
  40. static OSErr    vLogFileError   = true;        /* returned if LogStartup fails - logging can't be done */
  41. static FSSpec    vLogFileSpec;                /* the location of the log file */
  42. static short    vLogFileRef     = nil;        /* the reference of the open log file - nil if closed */
  43. static Boolean    vLogNeedsFlush  = false;    /* there is data that has been written but not flushed */
  44.  
  45.  
  46. /***  LOCAL CONSTANTS  ***/
  47.  
  48. #define krLogFileCreatorType        3002
  49. /* default to SimpleText/TeachText if creator type resource not available */
  50. #define kLogFileDefaultCreatorType    'ttxt'
  51.  
  52.  
  53. /***  LOCAL MACROS  ***/
  54.  
  55. #define logFileEnsureOpen()    ((vLogFileRef == nil)? LogFileOpen() : noErr)
  56.  
  57.  
  58. /***  LOCAL PROTOTYPES  ***/
  59.  
  60. /***  FUNCTIONS  ***/
  61.  
  62. /* Initialize the log file. */
  63. OSErr
  64. LogStartup ( void )
  65. {
  66.     Str255        logFileName;
  67.     Handle        logFileCreatorHdl;    /* the resource containing the creator type */
  68.     OSType        creatorType;        /* used when creating new log file */
  69.     Boolean        isFolder;            /* used for Finder alias resolving */
  70.     Boolean        wasAliased;            /* used for Finder alias resolving */
  71.     
  72.     vLogInitialized  = true;
  73.     vLogFileError    = noErr;
  74.     vLogFileRef      = nil;
  75.     logFileName[nil] = nil;
  76.     vLogNeedsFlush   = false;
  77.     
  78.     /* get the name of the log file */
  79.     GetIndString ( logFileName, krFilenamesStrs, kriFilenameLog );
  80.     if ( logFileName[nil] == nil )
  81.     {
  82.         /* string of file name is invalid */
  83.         vLogFileError = ResError ();
  84.     }
  85.     
  86.     /* build the FSSpec */
  87.     if ( vLogFileError == noErr )
  88.     {
  89.         vLogFileError = FSMakeFSSpec ( gProcessFSSpec.vRefNum, gProcessFSSpec.parID,
  90.             logFileName, &vLogFileSpec );
  91.     }
  92.     
  93.     if ( vLogFileError == fnfErr )
  94.     {
  95.         /* determine the creator type of the log file */
  96.         logFileCreatorHdl = GetResource ( 'TNAM', krLogFileCreatorType );
  97.         if ( logFileCreatorHdl != NULL )
  98.         {
  99.             creatorType = **((OSType **)logFileCreatorHdl);
  100.             ReleaseResource ( logFileCreatorHdl );
  101.         }
  102.         else
  103.         {
  104.             /* use default if creator type resource not found */
  105.             creatorType = kLogFileDefaultCreatorType;
  106.         }
  107.         vLogFileError = FSpCreate ( &vLogFileSpec, creatorType, kTypeText, smSystemScript );
  108.     }
  109.     else if ( vLogFileError == noErr )
  110.     {
  111.     /* resolve if the file is an alias */
  112.         vLogFileError = ResolveAliasFileMountOption ( &vLogFileSpec, true, &isFolder, &wasAliased, false );
  113.     }
  114.     
  115.     if ( vLogFileError == noErr )
  116.     {
  117.         vLogFileError = LogFileOpen ();
  118.     }
  119.     
  120.     #if kCompileWithDebugLogging
  121.     if ( vLogFileError == noErr )
  122.     {
  123.         LogStringAndSeparatorP    ( gProcessFSSpec.name, ' ' );
  124.         LogStringBreakP            ( gVersionStr );
  125.     }
  126.     #endif
  127.     
  128.     return vLogFileError;
  129. } /* LogStartup */
  130.  
  131.  
  132. /*  */
  133. OSErr
  134. LogQuit ( void )
  135. {
  136.     OSErr    theErr;
  137.     
  138.     if ( (vLogFileError == noErr) && (vLogFileRef != nil) )
  139.     {
  140.         theErr = LogFileClose ();
  141.     }
  142.     else
  143.     {
  144.         theErr = noErr;
  145.     }
  146.     
  147.     return theErr;
  148. } /* LogQuit */
  149.  
  150.  
  151. #pragma mark -
  152.  
  153. /* Open the log file for writing. Writing will begin at the end of the file (appending) */
  154. OSErr
  155. LogFileOpen ( void )
  156. {
  157.     OSErr    theErr;
  158.     
  159.     if ( vLogFileError == noErr )
  160.     {
  161.         my_assert ( vLogFileRef == nil, "\pLogFileOpen: vLogFileRef is not nil - file already open" );
  162.         
  163.         /* open the data fork for writing */
  164.         theErr = FSpOpenDF ( &vLogFileSpec, fsWrPerm, &vLogFileRef );
  165.         if ( theErr == noErr )
  166.         {
  167.             /* set the file position to the end of the file */
  168.             theErr = SetFPos ( vLogFileRef, fsFromLEOF, nil );
  169.         }
  170.         else
  171.         {
  172.             /* there was an error */
  173.             vLogFileRef = nil;
  174.         }
  175.     }
  176.     else
  177.     {
  178.         theErr = vLogFileError;
  179.     }
  180.     
  181.     return theErr;
  182. } /* LogFileOpen */
  183.  
  184.  
  185. /* Close the log file. */
  186. OSErr
  187. LogFileClose ( void )
  188. {
  189.     OSErr    theErr;
  190.     
  191.     if ( vLogFileError == noErr )
  192.     {
  193.         my_assert ( vLogFileRef != nil, "\pLogFileClose: vLogFileRef is nil" );
  194.         
  195.         theErr = FSClose ( vLogFileRef );
  196.         vLogFileRef = nil;
  197.     }
  198.     else
  199.     {
  200.         theErr = vLogFileError;
  201.     }
  202.     
  203.     return theErr;
  204. } /* LogFileClose */
  205.  
  206.  
  207. /* ••• need to upgrade this to just flush the data to disk - but I'm in a rush to
  208.     get this at least working...
  209.     This function should be called periodically after data has been written to the
  210.     log file. It helps to ensure that the data is not lost if there is a crash before
  211.     the file is closed. */
  212. p_export
  213. OSErr
  214. LogFileFlush ( void )
  215. {
  216.     OSErr    theErr;
  217.     
  218.     if ( vLogNeedsFlush )
  219.     {
  220.         theErr = LogFileClose ();
  221.         theErr = LogFileOpen ();
  222.         vLogNeedsFlush = false;
  223.     }
  224.     else
  225.     {
  226.         theErr = noErr;
  227.     }
  228.     
  229.     return theErr;
  230. } /* LogFileFlush */
  231.  
  232.  
  233. #pragma mark -
  234.  
  235. /* Takes a C format string and writes it to the log file.
  236.     Does not append linebreak or any other character so the next write to the log file
  237.     will follow directly after this write. If you want to have theString followed by
  238.     a linebreak, you need to call one of the functions that appends a separator
  239.     character after theString. */
  240. p_export
  241. OSErr
  242. LogString ( const char *theString )
  243. {
  244.     OSErr    theErr;
  245.     long    stringLength;
  246.     
  247.     my_assert ( theString != NULL, "\pLogString: theString is NULL" );
  248.     
  249.     if ( !vLogInitialized )
  250.     {
  251.         return noErr;
  252.     }
  253.     
  254.     if ( (vLogFileError == noErr) && (theString[nil] != nil) )
  255.     {
  256.         theErr = logFileEnsureOpen ();
  257.         if ( theErr == noErr )
  258.         {
  259.             stringLength = strlen ( theString );
  260.             
  261.             /* write the line + end null byte to the file */
  262.             theErr = FSWrite ( vLogFileRef, &stringLength, theString );
  263.             if ( theErr == noErr )
  264.             {
  265.                 vLogNeedsFlush = true;
  266.             }
  267.         }
  268.     }
  269.     else
  270.     {
  271.         theErr = vLogFileError;
  272.     }
  273.     
  274.     return theErr;
  275. } /* LogString */
  276.  
  277.  
  278. /* Same as 'LogString', except theString is a Pascal format string (max 255 characters) */
  279. p_export
  280. OSErr
  281. LogStringP ( const StringPtr theString )
  282. {
  283.     OSErr    theErr;
  284.     long    stringLength;
  285.     
  286.     my_assert ( theString != NULL, "\pLogStringP: theString is NULL" );
  287.     
  288.     if ( !vLogInitialized )
  289.     {
  290.         return noErr;
  291.     }
  292.     
  293.     if ( (vLogFileError == noErr) && (theString[nil] != nil) )
  294.     {
  295.         theErr = logFileEnsureOpen ();
  296.         if ( theErr == noErr )
  297.         {
  298.             stringLength = (unsigned char) (theString[nil]);
  299.             
  300.             /* write the line + end null byte to the file */
  301.             theErr = FSWrite ( vLogFileRef, &stringLength, theString + 1 );
  302.             if ( theErr == noErr )
  303.             {
  304.                 vLogNeedsFlush = true;
  305.             }
  306.         }
  307.     }
  308.     else
  309.     {
  310.         theErr = noErr;
  311.     }
  312.     
  313.     return theErr;
  314. } /* LogStringP */
  315.  
  316.  
  317. /* Takes a C format string and writes it to the log file.
  318.     Appends theSeparator after theString. This may be used for writing theString
  319.     followed by a linefeed, or perhaps a tab character, among other uses. */
  320. p_export
  321. OSErr
  322. LogStringAndSeparator ( const char *theString, char theSeparator )
  323. {
  324.     OSErr    theErr;
  325.     long    stringLength;
  326.     
  327.     my_assert ( theString != NULL, "\pLogStringAndSeparator: theString is NULL" );
  328.     
  329.     if ( !vLogInitialized )
  330.     {
  331.         return noErr;
  332.     }
  333.     
  334.     if ( vLogFileError == noErr )
  335.     {
  336.         theErr = logFileEnsureOpen ();
  337.         if ( theErr == noErr )
  338.         {
  339.             if ( theString[nil] != nil )
  340.             {
  341.                 stringLength = strlen ( theString );
  342.                 
  343.                 /* write the line + end null byte to the file */
  344.                 theErr = FSWrite ( vLogFileRef, &stringLength, theString );
  345.             }
  346.             
  347.             /* write the newline char to the file */
  348.             stringLength = 1;
  349.             theErr = FSWrite ( vLogFileRef, &stringLength, &theSeparator );
  350.             if ( theErr == noErr )
  351.             {
  352.                 vLogNeedsFlush = true;
  353.             }
  354.         }
  355.     }
  356.     else
  357.     {
  358.         theErr = noErr;
  359.     }
  360.     
  361.     return theErr;
  362. } /* LogStringAndSeparator */
  363.  
  364.  
  365. /* Same as 'LogStringAndSeparator', except theString is a Pascal format string
  366.     (max 255 characters) */
  367. p_export
  368. OSErr
  369. LogStringAndSeparatorP ( const StringPtr theString, char theSeparator )
  370. {
  371.     OSErr    theErr;
  372.     long    stringLength;
  373.     
  374.     my_assert ( theString != NULL, "\pLogStringAndSeparatorP: theString is NULL" );
  375.     
  376.     if ( !vLogInitialized )
  377.     {
  378.         return noErr;
  379.     }
  380.     
  381.     if ( vLogFileError == noErr )
  382.     {
  383.         theErr = logFileEnsureOpen ();
  384.         if ( theErr == noErr )
  385.         {
  386.             if ( theString[nil] != nil )
  387.             {
  388.                 stringLength = (unsigned char) (theString[nil]);
  389.                 
  390.                 /* write the line + end null byte to the file */
  391.                 theErr = FSWrite ( vLogFileRef, &stringLength, theString + 1 );
  392.             }
  393.             
  394.             /* write the newline char to the file */
  395.             stringLength = 1;
  396.             theErr = FSWrite ( vLogFileRef, &stringLength, &theSeparator );
  397.             if ( theErr == noErr )
  398.             {
  399.                 vLogNeedsFlush = true;
  400.             }
  401.         }
  402.     }
  403.     else
  404.     {
  405.         theErr = noErr;
  406.     }
  407.     
  408.     return theErr;
  409. } /* LogStringAndSeparatorP */
  410.  
  411.  
  412. /**  DEBUG LOGGING  **/
  413. #pragma mark -
  414. #if kCompileWithDebugLogging
  415.  
  416. /* These functions will prepend "DEBUG: " in the log file before writing theString
  417.     that is passed to them.
  418.     The functions are prototyped in "LogUtil.h" to map to NULL (do nothing) if
  419.     the 'kCompileWithDebugLogging' option is off in "MyConfiguration.h" */
  420.  
  421. /*  */
  422. p_export
  423. OSErr
  424. LogStringDebug ( const char *theString )
  425. {
  426.     OSErr    theErr;
  427.     
  428.     theErr = LogStringP ( "\pDEBUG: " );
  429.     theErr = LogStringAndSeparator ( theString, kLogLinebreak );
  430.     
  431.     return theErr;
  432. } /* LogStringDebug */
  433.  
  434.  
  435. /*  */
  436. p_export
  437. OSErr
  438. LogStringDebugP ( const StringPtr theString )
  439. {
  440.     OSErr    theErr;
  441.     
  442.     theErr = LogStringP ( "\pDEBUG: " );
  443.     theErr = LogStringAndSeparatorP ( theString, kLogLinebreak );
  444.     
  445.     return theErr;
  446. } /* LogStringDebugP */
  447.  
  448. #endif /* kCompileWithDebugLogging */
  449.  
  450.  
  451. #endif /* kCompileWithLogSupport */
  452. /*****  EOF  *****/
  453.